package avicit.bdp.oss.utils.upload.utils.common;

import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.util.ArrayList;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2020-12-09
 * @类说明：CommUtil
 * @修改记录：
 * @注意事项：
 * @主要功能：断点续传/分片上传通用工具类
 */
public class CommUtil {
    private static final Logger logger = LoggerFactory.getLogger(CommUtil.class);

    /**
     * 构建Redis中taskInfo使用的Key
     * @return
     */
    public static byte[] buildTaskInfoKey(String suiffix) {
        StringBuilder sb = new StringBuilder();
        sb.append(Constant.OSS_UPLOAD_TASK_INFO_KEY)
                .append(ThreadContextHelper.getUserId())
                .append(Constant.HYPHEN)
                .append(suiffix);

        return encode(sb.toString());
    }

    /**
     * 构建Redis中chunkInfo使用Key
     * @param taskId
     * @return
     */
    public static byte[] buildChunkInfoKey(String taskId) {
        StringBuilder sb = new StringBuilder();
        sb.append(Constant.OSS_UPLOAD_CHUNK_INFO_KEY)
                .append(Constant.HYPHEN)
                .append(ThreadContextHelper.getUserId())
                .append(Constant.HYPHEN)
                .append(taskId);

        return encode(sb.toString());
    }

    /**
     * 临时文件名称前缀，用于上传完成/Key过期后删除临时文件
     * @param objectName
     * @param taskId
     * @return
     */
    public static String buildTmpFileName(String objectName, int chunkNo, String taskId) {
        StringBuilder sb = new StringBuilder();

        return sb.append(getObjectPrefix(objectName))
                .append(Constant.HYPHEN)
                .append(taskId)
                .append(Constant.HYPHEN)
                .append(chunkNo)
                .append(Constant.DOT)
                .append(getObjectSuffix(objectName))
                .toString();
    }

    /**
     * 临时文件名称前缀，用于上传完成/Key过期后删除临时文件
     * @param objectName
     * @return
     */
    public static String buildTmpFileName(String objectName, int chunkNo) {
        StringBuilder sb = new StringBuilder();

        return sb.append(getObjectPrefix(objectName))
                .append(Constant.HYPHEN)
                .append(chunkNo)
                .append(Constant.DOT)
                .append(getObjectSuffix(objectName))
                .toString();
    }

    /**
     * 获取对象前缀名
     * @param objectName
     * @return
     */
    public static String getObjectPrefix(String objectName) {
        // 没有后缀的文件名称，例如：Dockerfile
        if (objectName.lastIndexOf(Constant.DOT) == -1) {
            return objectName;
        }

        return objectName.substring(0, objectName.lastIndexOf(Constant.DOT));
    }

    /**
     * 获取对象后缀名
     * @param objectName
     * @return
     */
    public static String getObjectSuffix(String objectName) {
        int lastIndexOf = objectName.lastIndexOf(Constant.DOT);
        if (lastIndexOf == -1 || lastIndexOf == objectName.length() - 1) {
            return "";
        }

        return objectName.substring(lastIndexOf + 1);
    }

    /**
     * 序列化
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();

            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 序列化
     * @param strs
     * @return
     */
    public static byte[] serialize(String[] strs) {
        ArrayList<Byte> byteList = new ArrayList<>();
        for (String str : strs) {
            int len = (str.getBytes()).length;
            ByteBuffer bb = ByteBuffer.allocate(4);
            bb.putInt(len);

            byte[] lenArray = bb.array();
            for (byte b : lenArray) {
                byteList.add(Byte.valueOf(b));
            }

            byte[] strArray = str.getBytes();
            for (byte b : strArray) {
                byteList.add(Byte.valueOf(b));
            }
        }
        byte[] result = new byte[byteList.size()];
        for (int i = 0; i < byteList.size(); i++) {
            result[i] = ((Byte)byteList.get(i)).byteValue();
        }

        return result;
    }

    /**
     * 反序列化
     * @param bytes
     * @return
     */
    public static Object unserialize(byte[] bytes) {
        ByteArrayInputStream bais = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 解密
     * @param strs
     * @return
     */
    public static byte[][] encodeMany(String... strs) {
        byte[][] many = new byte[strs.length][];
        for (int i = 0; i < strs.length; i++) {
            many[i] = encode(strs[i]);
        }

        return many;
    }

    /**
     * 加密
     * @param str
     * @return
     */
    public static byte[] encode(String str) {
        try {
            if (str == null || str.trim().length() == 0) {
                return new byte[0];
            }

            return str.getBytes("UTF-8");
        } catch (UnsupportedEncodingException unsupportedEncodingException) {
            return new byte[0];
        }
    }

    /**
     * 加密
     * @param data
     * @return
     */
    public static String encode(byte[] data) {
        try {
            if (data == null || data.length == 0) {
                return null;
            }

            return new String(data, "UTF-8");
        } catch (UnsupportedEncodingException unsupportedEncodingException) {
            return null;
        }
    }

    /**
     * 加密
     * @param data
     * @return
     */
    public static String encode(Object data) {
        try {
            return encode((byte[])data);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 检查Object非空
     * @param obj
     * @param errMsg
     */
    public static void validateObjectNotNull(Object obj, String errMsg) {
        if (obj == null) {
            printLogAndThrowException(errMsg);
        }
    }

    /**
     * 检查Object为空
     * @param obj
     * @param errMsg
     */
    public static void validateObjectNull(Object obj, String errMsg) {
        if (obj != null) {
            printLogAndThrowException(errMsg);
        }
    }

    /**
     * 检查String非空
     * @param para
     * @param errMsg
     */
    public static void validateStringNotNull(String para, String errMsg) {
        if (para == null || para.length() <= 0) {
            printLogAndThrowException(errMsg);
        }
    }

    /**
     * 记录日志，抛出异常信息
     * @param errMsg
     */
    public static void printLogAndThrowException(String errMsg) {
        logger.error(errMsg);
        throw new BusinessException(errMsg);
    }

    /**
     * 计算var2相对月var1的增加比例，保留两位小数
     * @param var1
     * @param var2
     * @return
     */
    public static String calRatio(int var1, int var2) {
        // 二者相等，增减0%
        if (var1 == var2) {
            return "0.00%";
        }

        // 前者为0L，默认增加100%
        if (var1 == 0L) {
            return "100.00%";
        }

        DecimalFormat decimalFormat = new DecimalFormat(Constant.PERCENT_FORMAT);
        double retVar = (double)var1 / (double)var2;

        return decimalFormat.format(retVar);
    }
}
